﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ControleRepresentanteSync.ControleRepresentanteServices;

namespace ControleRepresentanteSync.Logic
{
    internal interface IContractsProvider
    {
        IEnumerable<ImpostoContract> GetImpostos();
        IEnumerable<FabricaContract> GetFabricas();
        IEnumerable<TransportadoraContract> GetTransportadoras();
        IEnumerable<ClienteContract> GetClientes();
        IEnumerable<VendedorContract> GetVendedores();
        void Refresh();
        event EventHandler<ContractsProviderErrorEventArgs> Error;
        IEnumerable<RelatorioVisitaOcorrenciaContract> GetOcorrencias();
        void AddClientes(IEnumerable<ClienteContract> clientes);
        void AddTransportadoras(IEnumerable<TransportadoraContract> transportadoras);
        IEnumerable<AttributeContract> GetPedidoAttributes();
        IEnumerable<AttributeContract> GetRelatorioVisitaAttributes();
    }

    internal class ContractsProviderErrorEventArgs : EventArgs
    {
        public string ErrorMessage { get; private set; }

        public ContractsProviderErrorEventArgs(string message)
        {
            ErrorMessage = message;
        }
    }

    class ContractsProvider : IContractsProvider
    {
        private readonly ISyncServiceProvider m_SyncServiceProvider;
        private ImpostoContract[] m_Impostos;
        private FabricaContract[] m_Fabricas;
        private List<TransportadoraContract> m_Transportadoras;
        private List<ClienteContract> m_Clientes;
        private VendedorContract[] m_Vendedores;
        private bool m_IsRefreshing;
        private RelatorioVisitaOcorrenciaContract[] m_Ocorrencias;
        private AttributeContract[] m_PedidoAttributes;
        private AttributeContract[] m_RelatorioVisitaAttributes;

        public ContractsProvider(ISyncServiceProvider syncServiceProvider)
        {
            m_SyncServiceProvider = syncServiceProvider;
            Refresh();
        }

        public IEnumerable<ImpostoContract> GetImpostos()
        {
            return WitForRefreshAndReturn(() => m_Impostos);
        }

        public IEnumerable<FabricaContract> GetFabricas()
        {
            return WitForRefreshAndReturn(() => m_Fabricas);
        }

        public IEnumerable<TransportadoraContract> GetTransportadoras()
        {
            return WitForRefreshAndReturn(() => m_Transportadoras);
        }

        public IEnumerable<ClienteContract> GetClientes()
        {
            return WitForRefreshAndReturn(() => m_Clientes);
        }

        public IEnumerable<VendedorContract> GetVendedores()
        {
            return WitForRefreshAndReturn(() => m_Vendedores);
        }

        private T WitForRefreshAndReturn<T>(Func<T> func)
        {
            while (m_IsRefreshing)
            {
                Thread.Sleep(1000);
            }
            return func();
        }

        public void Refresh()
        {
            if (m_IsRefreshing) return;

            Thread thread = new Thread(() =>
            {
                m_IsRefreshing = true;
                try
                {
                    m_SyncServiceProvider.Execute(syncService =>
                    {
                        m_Impostos = syncService.GetImpostos();
                        m_Fabricas = syncService.GetJolitexFabricas();
                        m_Transportadoras = syncService.GetTransportadoras().ToList();
                        m_Clientes = syncService.GetClientes().ToList();
                        m_Vendedores = syncService.GetVendedores();
                        m_Ocorrencias = syncService.GetRelatorioVisitaOcorrencias();
                        m_PedidoAttributes = syncService.GetPeditoAttributes();
                        m_RelatorioVisitaAttributes = syncService.GetRelatorioVisitaAttributes();
                    });
                }
                catch (Exception e)
                {
                    m_Impostos = new ImpostoContract[0];
                    m_Fabricas = new FabricaContract[0];
                    m_Transportadoras = new List<TransportadoraContract>();
                    m_Clientes = new List<ClienteContract>();
                    m_Vendedores = new VendedorContract[0];
                    m_Ocorrencias = new RelatorioVisitaOcorrenciaContract[0];
                    m_PedidoAttributes = new AttributeContract[0];
                    m_RelatorioVisitaAttributes = new AttributeContract[0];
                    FireError(e.Message);
                }
                finally
                {
                    m_IsRefreshing = false;
                }
            });
            thread.Start();
        }

        public event EventHandler<ContractsProviderErrorEventArgs> Error;

        public IEnumerable<RelatorioVisitaOcorrenciaContract> GetOcorrencias()
        {
            return WitForRefreshAndReturn(() => m_Ocorrencias);
        }

        public void AddClientes(IEnumerable<ClienteContract> clientes)
        {
            m_Clientes.AddRange(clientes);
        }

        public void AddTransportadoras(IEnumerable<TransportadoraContract> transportadoras)
        {
            m_Transportadoras.AddRange(transportadoras);
        }

        public IEnumerable<AttributeContract> GetPedidoAttributes()
        {
            return m_PedidoAttributes;
        }

        public IEnumerable<AttributeContract> GetRelatorioVisitaAttributes()
        {
            return m_RelatorioVisitaAttributes;
        }

        private void FireError(string message)
        {
            if (Error != null)
                Error(this, new ContractsProviderErrorEventArgs(message));
        }
    }
}
